package indi.h.security.encryption.sym;

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import indi.h.security.Parameters;
import indi.h.security.encryption.AbstractCrypt;
import indi.h.security.encryption.SymCrypt;

public class SymCryptImp extends AbstractCrypt implements SymCrypt {
	protected Cipher cipher;
	protected SymCryptParameter params;
	protected SecretKey secretKey;

	protected SymCryptImp() {
		
	}

	@Override
	public byte[] encrypt(byte[] data) {
		super.encrypt(data);
		try {
			return cipher.doFinal(data);
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		} catch (BadPaddingException e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public byte[] decrypt(byte[] data) {
		super.decrypt(data);
		try {
			return cipher.doFinal(data);
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		} catch (BadPaddingException e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public String getAlgorithm() {
		return params.getAlgorithm();
	}

	@Override
	public byte[] getSecretKey() {
		return secretKey.getEncoded();
	}

	@Override
	public void init() {
		try {
			cipher = Cipher.getInstance(params.getCipherAlgorithm());
			if (params.getSecretKey() != null)
				secretKey = createKeySpec();
			customInit();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 
	 * key length=params.getLength()/8
	 * 
	 */
	public void customInit() {
		if (secretKey != null)
			return;
		KeyGenerator keyGenerator;
		try {
			keyGenerator = KeyGenerator.getInstance(params.getAlgorithm());
			keyGenerator.init(params.getLength(), new SecureRandom(params.getPassword().getBytes(params.getCode())));
			secretKey = keyGenerator.generateKey();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
	}

	public SecretKey createKeySpec() {
		return new SecretKeySpec(params.getSecretKey(), params.getAlgorithm());
	}

	@Override
	public Integer getLength() {
		return params.getLength();
	}

	@Override
	public void setParams(Parameters param) {
		params = (SymCryptParameter) param;
	}

	@Override
	public void beforeEncrypt() {
		try {
			cipher.init(Cipher.ENCRYPT_MODE, secretKey);
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		}
	}

	@Override
	public void beforeDecrypt() {
		try {
			cipher.init(Cipher.DECRYPT_MODE, secretKey);
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		}
	}

	@Override
	public String getCipherAlgorithm() {
		return cipher.getAlgorithm();
	}

}
